package com.dag.account.service.impl;

import com.alibaba.fastjson.JSON;
import com.dag.account.api.dto.account.BusinessTransferReqDTO;
import com.dag.account.api.dto.account.BusinessTransferRespDTO;
import com.dag.account.api.dto.account.TransferReqDTO;
import com.dag.account.api.dto.account.TransferRespDTO;
import com.dag.account.constants.*;
import com.dag.account.dao.entity.Account;
import com.dag.account.dao.entity.Member;
import com.dag.account.dao.entity.TradeRecord;
import com.dag.account.service.IAccountService;
import com.dag.account.service.IMemberService;
import com.dag.account.service.ITradeRecordService;
import com.dag.account.service.ITransferService;
import com.dag.account.utils.TradeUtils;
import com.dag.common.exception.BusinessRuntimeException;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * 转账操作类
 * @author 孙建
 */
@Service
public class TransferServiceImpl implements ITransferService {

    @Autowired
    private IAccountService accountService;
    @Autowired
    private ITradeRecordService tradeRecordService;
    @Autowired
    private IMemberService memberService;

    /**
     * 转账
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public TransferRespDTO transfer(TransferReqDTO transferDTO) {
        Integer draweeAccountType = transferDTO.getDraweeAccountType();
        Integer payeeAccountType = transferDTO.getPayeeAccountType();
        String operatorName = transferDTO.getOperatorName();
        Account draweeAccount = accountService.queryByMemberIdAndAccountType(transferDTO.getDraweeMemberId(), draweeAccountType);
        Account payeeAccount = accountService.queryByMemberIdAndAccountType(transferDTO.getPayeeMemberId(), payeeAccountType);

        // 校验账户
        TransferRespDTO transferRespDTO = validateTransfer(transferDTO, draweeAccount, payeeAccount);
        // 校验通过
        if(transferRespDTO.isSuccess()){
            BigDecimal transferAmount = transferDTO.getAmount();
            // 付款账户减钱
            accountService.deduction(draweeAccount, transferAmount, operatorName);
            // 收款账户加钱
            accountService.add(payeeAccount, transferAmount, operatorName);
            // 生成转账交易记录
            TradeRecord tradeRecord = saveTransferTradeRecord(transferDTO, draweeAccount, payeeAccount);

            // 设置转账结果字段
            transferRespDTO.setSerialNo(tradeRecord.getSerialNo());
            transferRespDTO.setMessage("转账成功");
        }
        return transferRespDTO;
    }


    /**
     * 业务转账
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BusinessTransferRespDTO businessTransfer(BusinessTransferReqDTO transferDTO) {
        List<TransferReqDTO> transferReqList = transferDTO.getTransferReqList();
        for (TransferReqDTO transferReqDTO : transferReqList) {
            // 转账
            TransferRespDTO transferRespDTO = this.transfer(transferReqDTO);
            if(!transferRespDTO.isSuccess()){
                throw new BusinessRuntimeException(JSON.toJSON(transferRespDTO).toString());
            }
        }
        return BusinessTransferRespDTO.bySuccess("转账成功");
    }


    /**
     * 生成转账交易记录
     */
    private TradeRecord saveTransferTradeRecord(TransferReqDTO transferDTO, Account draweeAccount, Account payeeAccount) {
        // 交易本人
        TradeRecord tradeRecord = new TradeRecord();
        tradeRecord.setSerialNo(TradeUtils.buildSeqNo());
        tradeRecord.setTradeVoucherNo(transferDTO.getTradeVoucherNo());
        tradeRecord.setMemberId(draweeAccount.getMemberId());
        tradeRecord.setMemberName(transferDTO.getDraweeMemberName());
        tradeRecord.setAccountId(draweeAccount.getId());
        tradeRecord.setOtherMemberId(payeeAccount.getMemberId());
        tradeRecord.setOtherMemberName(transferDTO.getPayeeMemberName());
        tradeRecord.setOtherAccountId(payeeAccount.getId());
        tradeRecord.setTradeType(TradeTypeEnum.TRANSFER.getIndex());
        tradeRecord.setTradeTypeName(TradeTypeEnum.TRANSFER.getText());
        tradeRecord.setTradeChannel(TradeChannelEnum.ACCOUNT.getIndex());
        tradeRecord.setAmount(transferDTO.getAmount().abs().multiply(BigDecimal.valueOf(-1)));
        tradeRecord.setTradeSubject(transferDTO.getTradeSubject());
        tradeRecord.setTradeContent(transferDTO.getTradeContent());
        tradeRecord.setFundFlowType(FundFlowTypeEnum.PAY.getIndex());
        tradeRecord.setTradeStatus(TradeStatusEnum.TRADE_STATUS_SUCCESS.getIndex());
        tradeRecord.setTradeTime(new Date());
        tradeRecord.setCreateTime(new Date());
        tradeRecord.setCreaterId(transferDTO.getOperatorId());
        tradeRecord.setUpdaterId(transferDTO.getOperatorId());
        tradeRecord.setOrgId(draweeAccount.getOrgId());
        tradeRecord.setMerchantId(draweeAccount.getMerchantId());
        // 交易对方
        TradeRecord otherTradeRecord = TradeUtils.copyAndReverse(tradeRecord);
        // 保存交易记录
        tradeRecordService.saveBatch(Lists.newArrayList(tradeRecord, otherTradeRecord));
        return tradeRecord;
    }


    /**
     * 转账校验
     */
    private TransferRespDTO validateTransfer(TransferReqDTO transferDTO, Account draweeAccount, Account payeeAccount) {
        String tradeVoucherNo = transferDTO.getTradeVoucherNo();
        if(draweeAccount == null){
            return TransferRespDTO.byFail(null, tradeVoucherNo, "付款账户不存在");
        }
        if(payeeAccount == null){
            return TransferRespDTO.byFail(null, tradeVoucherNo, "收款账户不存在");
        }

        Member draweeMember = memberService.getById(transferDTO.getDraweeMemberId());
        if(draweeMember == null){
            return TransferRespDTO.byFail(null, tradeVoucherNo, "付款人不存在");
        }
        Member payeeMember = memberService.getById(transferDTO.getPayeeMemberId());
        if(payeeMember == null){
            return TransferRespDTO.byFail(null, tradeVoucherNo, "收款人不存在");
        }

        // 判断交易是否已经操作过
        TradeRecord tradeRecord = tradeRecordService.queryByTradeVoucherNo(tradeVoucherNo, TradeTypeEnum.TRANSFER.getIndex(),
                FundFlowTypeEnum.PAY.getIndex(), TradeStatusEnum.TRADE_STATUS_SUCCESS.getIndex());
        if(tradeRecord != null){
            return TransferRespDTO.byFail(tradeRecord.getSerialNo(), tradeVoucherNo, "交易业务单号已完成交易，请检查");
        }

        Integer draweeAccountStatus = draweeAccount.getStatus();
        if(draweeAccountStatus != AccountStatusEnum.VALID.getIndex()){
            return TransferRespDTO.byFail(null, tradeVoucherNo, "付款账户状态异常");
        }
        Integer payeeAccountStatus = payeeAccount.getStatus();
        if(payeeAccountStatus != AccountStatusEnum.VALID.getIndex()){
            return TransferRespDTO.byFail(null, tradeVoucherNo, "收款账户状态异常");
        }

        // 判断付款账户余额是否充足
        BigDecimal amount = transferDTO.getAmount();
        if(draweeAccount.getBalanceAmount().compareTo(amount) < 0){
            return TransferRespDTO.byFail(null, tradeVoucherNo, "付款账户余额不足");
        }

        // 补充数据
        transferDTO.setDraweeMemberName(draweeMember.getMemberName());
        transferDTO.setPayeeMemberName(payeeMember.getMemberName());
        return TransferRespDTO.bySuccess(null, tradeVoucherNo, "校验通过");
    }


}
